package jdk.utils;

import java.util.*;
import java.util.Collections;
import java.util.UUID;
import java.util.Vector;
import java.util.concurrent.CopyOnWriteArrayList;


/**
 * 集合类ArrayList线程不安全的原因：add因为要保证效率，所以没有加锁,写的时候线程争抢资源导致并发修改异常
 * 由于他是由数组构成的，所以该集合类框架对于随机访问的效率很高，时间复杂度为 O(1)。
 *   1. DEFAULT_CAPACITY = 10;默认容量是10
 *   2.插入元素的时候，add(E e)便会在数组的末端插入，时间复杂度近似为 O(1)
 *    如果在数组中间插入一个元素，那么他会先将该位置后面的元素整体往后移动一位后，再把待插入元素插入，这时的时间复杂度就近似为 O(n)。
 * 扩容底层原理：
 *   1.如果插入元素的大小大于了数组容量，则扩容，默认是扩容1.5倍。集合中的元素数量与存储数组的长度一样的时候，会触发扩容机制，
 *   会把当前数组的长度左移 1位 作为扩容判断的标准，并计算出新的大小 newCapacity（约为当前数组长度的1.5倍）
 *
 *
 */
public class ArrayList_study {

    volatile static ArrayList<String> arrayList = new ArrayList();

    //实现集合线程安全的集方式：

    volatile static Vector<String> vactor = new Vector();

    volatile static List<String> synchronizationList = Collections.synchronizedList(new ArrayList<String>());

    /**
     * CopyOnWriteArrayList 的add 思想：
     *     CopyOnWrite 既写时候复制的容器，往一个容器中添加元素的时候，不是直接往里面添加，而是对Object[] 数组进行复制，
     *     复制一个新的数组然后在里面添加元素，添加元素后，再将原容器引用指向新的容器，这样做的好处是可以对CopyOnWrite容器
     *     进行并发的读，而不需要加锁，因为当前元素不会添加任何元素。所以CopyOnWrite是一种读写分离的思想。读和写不同的容器
     *
     *     主要通过System.arrayCopy（）复制
     *
     */
    volatile static List<String> copyOnWriteArrayList = new CopyOnWriteArrayList<>();

    public static void main(String[] args) {

        ArrayList<String> linkedList = new ArrayList<>();
        linkedList.add("aaa");
        linkedList.add("bbb");
        linkedList.add("ccc");
        linkedList.add("ddd");
        linkedList.stream().forEach(System.out::println);

        //下面是使用5个线程各写一次   会出现结果：[null, 0ef47491, 35836bed, ceedfb67, bde83ee5]
        //原因：add没有加锁，甚至会报错：java.util.ConcurrentModificationException
        //怎么解决：1.使用线程安全的集合 比如Vector 可以解决，但是效率很低
        //2.使用synchronizedList 来解决
        //3.使用CopyOnWriteArrayList
        for (int i = 0; i < 50; i++) {
            new Thread(() -> {
                copyOnWriteArrayList.add(UUID.randomUUID().toString().substring(0, 8));
            }, String.valueOf(i)).start();

        }
        while (Thread.activeCount() > 2) {
            Thread.yield();
        }
        System.out.println(copyOnWriteArrayList);
    }
}
